package com.ckzp.jfinal.plugins.cron4j;

import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.IPlugin;
import com.jfinal.plugin.cron4j.ITask;
import it.sauronsoftware.cron4j.ProcessTask;
import it.sauronsoftware.cron4j.Scheduler;
import it.sauronsoftware.cron4j.Task;
import org.apache.log4j.Logger;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by 51594 on 2022/7/28.
 */
public class MyCron4jPlugin implements IPlugin {

    public static MyCron4jPlugin plugin = null;


    private static final Logger log = Logger.getLogger(MyCron4jPlugin.class);


    private List<TaskInfo> taskInfoList = new ArrayList<TaskInfo>();

    public static final String defaultConfigName = "cron4j";

    public static String defaltPropName = "task.properties";

    public static MyCron4jPlugin n(Prop configProp) {
        if (plugin == null) plugin = new MyCron4jPlugin(configProp);
        return plugin;
    }


    public static MyCron4jPlugin n(String propName) {
        Prop configProp = PropKit.use(propName);
        if (plugin == null) plugin = new MyCron4jPlugin(configProp);
        return plugin;
    }


    public static MyCron4jPlugin n() {
        Prop configProp = PropKit.use(defaltPropName);
        if (plugin == null) plugin = new MyCron4jPlugin(configProp);
        return plugin;
    }


    public static MyCron4jPlugin getPlugin() {
        if (plugin == null) plugin = new MyCron4jPlugin();
        return plugin;
    }

    /**
     * 手工启动
     *
     * @param taskName
     * @return
     */
    public static boolean startTask(String taskName) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                if (!info.isStatus()) {
                    info.start();
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 任务状态
     *
     * @param taskName
     * @return
     */
    public static boolean getTaskStatus(String taskName) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                return info.isStatus();
            }
        }
        return false;
    }


    /**
     * 任务状态
     *
     * @param taskName
     * @return
     */
    public static boolean hasTask(String taskName) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                return true;
            }
        }
        return false;
    }

    /**
     * 手工启动
     *
     * @param taskName
     * @return
     */
    public static boolean logTask(String taskName, boolean log) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                info.log(log);
                return true;
            }
        }
        return false;
    }

    /**
     * 手工ting
     *
     * @param taskName
     * @return
     */
    public static boolean stopTask(String taskName) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                if (info.isStatus()) {
                    info.stop();
                    getPlugin().getTaskInfoList().remove(info);
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * \删除任务
     *
     * @param taskName
     * @return
     */
    public static boolean removeTask(String taskName) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                if (info.isStatus()) {
                    getPlugin().getTaskInfoList().remove(info);
                    return true;
                }
            }
        }
        return true;
    }

    /**
     * 手工ting
     *
     * @param taskName
     * @return
     */

    public static boolean runTask(String taskName) {
        for (TaskInfo info : getPlugin().getTaskInfoList()) {
            if (taskName.equals(info.getName())) {
                info.run();
                return true;
            }
        }
        return false;
    }

    public MyCron4jPlugin() {

    }

    public MyCron4jPlugin(String configFile) {
        this(new Prop(configFile), defaultConfigName);
    }

    public MyCron4jPlugin(Prop configProp) {
        this(configProp, defaultConfigName);
    }

    public MyCron4jPlugin(String configFile, String configName) {
        this(new Prop(configFile), configName);
    }

    public MyCron4jPlugin(Prop configProp, String configName) {
        try {
            addTask(configProp, configName);
        } catch (RuntimeException e) {
            e.printStackTrace();
            // throw e;
        } catch (Exception e) {
            e.printStackTrace();
            // throw new RuntimeException(e);
        }
    }

    /**
     * 取得实例列表
     *
     * @return
     */
    public List<TaskInfo> getTaskInfoList() {
        return taskInfoList;
    }

    /*
         * 考虑添加对 ProcessTask 的配置支持，目前不支持 ProcessTask 对象的构造方法的参数配置
         * 对于 ProcessTask 型的任务调度，建议对 ProcessTask 的创建使用 java 代码
         */
    private void addTask(Prop configProp, String configName) throws Exception {
        String configNameValue = configProp.get(configName);
        if (StrKit.isBlank(configNameValue)) {
            //如果配置文件不存在，打印出配置文件不存在的提醒信息，而不是抛出错误，如果抛出错误，会造成应用启动不起来
            //if (ConfigUtil.DEBUG()) {
            log.error("cron配置文件错误:configName[" + configName + "]不能为空");
            return;
            // }
            //  throw new IllegalArgumentException("The value of configName: " + configName + " can not be blank.");
        }
        String[] taskNameArray = configNameValue.trim().split(",");
        for (String taskName : taskNameArray) {
            if (StrKit.isBlank(taskName)) {
                throw new IllegalArgumentException("taskName can not be blank.");
            }
            taskName = taskName.trim();

            String taskCron = configProp.get(taskName + ".cron");
            if (StrKit.isBlank(taskCron)) {
                throw new IllegalArgumentException(taskName + ".cron" + " not found.");
            }
            taskCron = taskCron.trim();

            String taskClass = configProp.get(taskName + ".class");
            if (StrKit.isBlank(taskClass)) {
                throw new IllegalArgumentException(taskName + ".class" + " not found.");
            }
            taskClass = taskClass.trim();

            Object taskObj = Class.forName(taskClass).newInstance();
            if (!(taskObj instanceof Runnable) && !(taskObj instanceof Task)) {
                throw new IllegalArgumentException("Task 必须是 Runnable、ITask、ProcessTask 或者 Task 类型");
            }

            boolean taskDaemon = configProp.getBoolean(taskName + ".daemon", true);
            boolean taskEnable = configProp.getBoolean(taskName + ".enable", true);
            taskInfoList.add(new TaskInfo(taskName, taskCron, taskObj, taskDaemon, taskEnable));
        }
    }

    public MyCron4jPlugin addTask(String taskName, String cron, Runnable task, boolean daemon, boolean enable) {
        taskInfoList.add(new TaskInfo(taskName, cron, task, daemon, enable));
        return this;
    }


    public MyCron4jPlugin addTask(String taskName, String cron, Runnable task, boolean daemon, boolean enable, boolean logs) {
        TaskInfo info = new TaskInfo(taskName, cron, task, daemon, enable);
        info.setLogs(logs);
        info.schedule();
        info.start();
        taskInfoList.add(info);
        return this;
    }

    public MyCron4jPlugin addTask(String taskName, String cron, Runnable task, boolean daemon) {
        return addTask(taskName, cron, task, daemon, true);
    }

    public MyCron4jPlugin addTask(String taskName, String cron, Runnable task) {
        return addTask(taskName, cron, task, true, true);
    }

    public MyCron4jPlugin addTask(String taskName, String cron, ProcessTask processTask, boolean daemon, boolean enable) {
        taskInfoList.add(new TaskInfo(taskName, cron, processTask, daemon, enable));
        return this;
    }

    public MyCron4jPlugin addTask(String taskName, String cron, ProcessTask processTask, boolean daemon) {
        return addTask(taskName, cron, processTask, daemon, true);
    }

    public MyCron4jPlugin addTask(String taskName, String cron, ProcessTask processTask) {
        return addTask(taskName, cron, processTask, true, true);
    }

    public MyCron4jPlugin addTask(String taskName, String cron, Task task, boolean daemon, boolean enable) {
        taskInfoList.add(new TaskInfo(taskName, cron, task, daemon, enable));
        return this;
    }

    public MyCron4jPlugin addTask(String taskName, String cron, Task task, boolean daemon, boolean enable, boolean logs) {
        TaskInfo info = new TaskInfo(taskName, cron, task, daemon, enable);
        info.setLogs(logs);
        info.schedule();
        info.start();
        taskInfoList.add(info);
        return this;
    }


    public MyCron4jPlugin addTask(String taskName, String cron, Task task, boolean daemon) {
        return addTask(taskName, cron, task, daemon, true);
    }

    public MyCron4jPlugin addTask(String taskName, String cron, Task task) {
        return addTask(taskName, cron, task, true, true);
    }

    public boolean start() {
        for (TaskInfo taskInfo : taskInfoList) {
            taskInfo.schedule();
        }
        for (TaskInfo taskInfo : taskInfoList) {
            taskInfo.start();
        }
        return true;
    }

    public boolean stop() {
        for (TaskInfo taskInfo : taskInfoList) {
            taskInfo.stop();
        }
        return true;
    }

    public static class TaskInfo {
        Scheduler scheduler;
        //运行中
        boolean status = true;
        String name;
        String cron;
        Object task;
        boolean daemon;
        boolean enable;
        boolean logs;

        public String getName() {
            return name;
        }

        public String getCron() {
            return cron;
        }

        public Object getTask() {
            return task;
        }

        public boolean isDaemon() {
            return daemon;
        }

        public boolean isEnable() {
            return enable;
        }

        public boolean isStatus() {
            return status;
        }

        public boolean isLogs() {
            return logs;
        }

        public void setLogs(boolean logs) {
            this.logs = logs;
        }

        public void setName(String name) {
            this.name = name;
        }

        TaskInfo(String name, String cron, Object task, boolean daemon, boolean enable) {
            if (StrKit.isBlank(name)) {
                throw new IllegalArgumentException("name 不能为空.");
            }
            if (StrKit.isBlank(cron)) {
                throw new IllegalArgumentException("cron 不能为空.");
            }
            if (task == null) {
                throw new IllegalArgumentException("task 不能为 null.");
            }

            this.name = name.trim();
            this.cron = cron.trim();
            this.task = task;
            this.daemon = daemon;
            this.enable = enable;
        }

        void schedule() {
            if (enable) {
                scheduler = new Scheduler();
                if (task instanceof Runnable) {
                    scheduler.schedule(cron, (Runnable) task);
                } else if (task instanceof Task) {
                    scheduler.schedule(cron, (Task) task);
                } else {
                    scheduler = null;
                    throw new IllegalStateException("Task 必须是 Runnable、ITask、ProcessTask 或者 Task 类型");
                }
                if (task instanceof MyTask) {
                    ((MyTask) task).setName(name);
                    ((MyTask) task).setLog(logs);
                }
                scheduler.setDaemon(daemon);
            }
        }

        void log(boolean logs) {
            if (task instanceof MyTask) {
                ((MyTask) task).setLog(logs);
            }
        }


        void name(String name) {
            if (task instanceof MyTask) {
                ((MyTask) task).setName(name);
            }
        }

        void run() {
            if (enable) {
                if (task instanceof Runnable) {
                    ((Runnable) task).run();
                }
            }
        }

        void start() {
            if (enable) {
                scheduler.start();
                status = true;
            }
        }

        void stop() {
            if (enable) {
                if (task instanceof ITask) {   // 如果任务实现了 ITask 接口，则回调 ITask.stop() 方法
                    ((ITask) task).stop();
                }
                scheduler.stop();
                status = false;
            }
        }
    }

}
